/*
 * This file is part of the Sx Framework Library.
 * 
 * Copyright (C) 2013 University of Colorado Denver
 * <min.choi@ucdenver.edu> <shane.transue@ucdenver.edu>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy 
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
 * copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in 
 * all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
 * DEALINGS IN THE SOFTWARE.
 */
#ifndef SX_OBJ_FILE_H
#define SX_OBJ_FILE_H

#include <sxString.h>
#include <sxOBJ_Face.h>
#include <sxProgressMonitorable.h>

namespace Sx {
namespace Graphics {
namespace File {

struct OBJ_FileDefinition;

/*
 * An OBJ file holds the definition of one or more geometric objects contained 
 * within a (Wavefront) .obj file.
 * TODO: Implement saving compression (elimination of duplicate vertices etc.)
 */
class OBJ_File : public Task::ProgressMonitorable {
public:

	OBJ_File();

	/*
	 * Creates a new OBJ file definition from the provided data. This will 
	 * only create an OBJ file with an individual mesh. The data arrays
	 * must adhere to the following conditions:
	 *	vertices.size() = n
	 *  normals.size() = n
	 *  textureCoords.size() = n
	 *  indices.size() = (# of faces) * (# of edges for a face)
	 *  groupIndices.size() = (# of faces)
	 *  materialIndices.size() = (# of faces)
	 *  smoothingGroupIndices.size() = (# of faces)
	 */
	OBJ_File(const String& name, const Util::VectorArray& vertices, const Util::VectorArray& normals, const Util::VectorArray& textureCoords, const Util::IndexArray& indices, const Util::IndexArray& groupIndices, const Util::IndexArray& materialIndices, const Util::IndexArray& smoothingGroupIndices, unsigned int faceDegree);
	virtual ~OBJ_File();
	
	/*
	 * Load an OBJ file into an OBJ file definition. The definition can then
	 * be accessed through this class to retrieve the loaded information.
	 * See OBJ_File::getDefinition()
	 */
	bool load(const String& filename);
	bool save(const String& filename, bool writeNormals = true, bool writeTextureCoords = true);

	void setCompressOnSave(bool compress);
	String getFaceMaterial(const OBJ_Face& face) const;
	String getFaceGroup(const OBJ_Face& face) const;

	/*
	 * The definition of the loaded OBJ file is contained within this file
	 * definition. The information in this file definition can be used to
	 * construct geometric objects by selectively using the components from
	 * the loaded file.
	 */
	OBJ_FileDefinition const * const getDefinition() const;

	static const String OBJ_FILE_EXTENSION;

private:
	/*
	 * Since OBJ files can contain complex information for several
	 * mesh objects and materials, all of the information that defines
	 * those properties of an OBJ file are stored in an OBJ file
	 * definition. To add to the capabilities of the OBJ file parser
	 * additional information may need to be added to the OBJ file
	 * definition class to hold the newly parsed information.
	 */
	OBJ_FileDefinition* fileDefinition;

	/*
	 * Defines whether or not this file is compressed when it is saved. If true
	 * this OBJ file representation will be written with all duplicate data
	 * removed while maintaining proper indexing. All OBJ files are decompressed
	 * by default.
	 */
	bool compressOnSave;

	/*
	* Helper function for saving. This is included in the class definition so
	* that detailed information can be provided to the progress monitor.
	* This function saves the mesh at the provided index from the file
	* definition in this class.
	*/
	bool saveObject(std::ostream& out, unsigned int meshIndex, bool writeNormals, bool writeTextureCoords);
	bool saveObjectCompressed(std::ostream& out, unsigned int meshIndex, bool writeNormals, bool writeTextureCoords);
};

}

}

}

#endif
